<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Drawing with Cairo in GTK#</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, GTK#, Cairo, drawing, C#, programming, Linux">
<meta name="description" content="In this part of the GTK# tutorial, we 
do some drawing with Cairo library.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">
</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Drawing with Cairo</h1>

<p>
In this part of the GTK# programming tutorial, we will do some drawing 
with the Cairo library.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>
<b>Cairo</b> is a library for creating 2D vector graphics. 
We can use it to draw our own widgets, charts or various effects or animations. 
</p>


<h2>Simple drawing</h2>

<p>
The stroke operation draws the outlines of shapes and the 
fill operation fills the insides of shapes. Next we will demonstrate
these two operations.
</p>

<div class="codehead">simpledrawing.cs</div> 
<pre class="code">
using Gtk;
using Cairo;
using System;
 
class SharpApp : Window {
 

    public SharpApp() : base("Simple drawing")
    {
        SetDefaultSize(230, 150);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };;
        
        DrawingArea darea = new DrawingArea();
        darea.ExposeEvent += OnExpose;

        Add(darea);

        ShowAll();
    }

    void OnExpose(object sender, ExposeEventArgs args)
    {
        DrawingArea area = (DrawingArea) sender;
        Cairo.Context cr =  Gdk.CairoHelper.Create(area.GdkWindow);
        
        cr.LineWidth = 9;
        cr.SetSourceRGB(0.7, 0.2, 0.0);
                
        int width, height;
        width = Allocation.Width;
        height = Allocation.Height;

        cr.Translate(width/2, height/2);
        cr.Arc(0, 0, (width &lt; height ? width : height) / 2 - 10, 0, 2*Math.PI);
        cr.StrokePreserve();
        
        cr.SetSourceRGB(0.3, 0.4, 0.6);
        cr.Fill();
         
        ((IDisposable) cr.Target).Dispose();                                      
        ((IDisposable) cr).Dispose();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}
</pre>

<p>
In our example, we will draw a circle and will it with a solid color. 
</p>

<pre>
gmcs -pkg:gtk-sharp-2.0 -r:/usr/lib/mono/2.0/Mono.Cairo.dll  simple.cs
</pre>

<p>
Here is how we compile the example. 
</p>

<pre class="explanation">
DrawingArea darea = new DrawingArea();
</pre>

<p>
We will be doing our drawing operations on the <code>DrawingArea</code> 
widget. 
</p>

<pre class="explanation">
darea.ExposeEvent += OnExpose;
</pre>

<p>
All drawing is done in a method, that we plug into
the <code>ExposeEvent</code>.
</p>

<pre class="explanation">
DrawingArea area = (DrawingArea) sender;
Cairo.Context cr =  Gdk.CairoHelper.Create(area.GdkWindow);
</pre>

<p>
We create the <code>Cairo.Context</code> object from the
<code>GdkWindow</code> of the drawing area.  The context is an
object that is used to draw on all Drawable objects. 
</p>

<pre class="explanation">
cr.LineWidth = 9;
</pre>

<p>
We set the width of the line to 9 pixels.
</p>

<pre class="explanation">
cr.SetSourceRGB(0.7, 0.2, 0.0);
</pre>

<p>
We set the color to dark red. 
</p>

<pre class="explanation">
int width, height;
width = Allocation.Width;
height = Allocation.Height;

cr.Translate(width/2, height/2);
</pre>

<p>
We get the width and height of the drawing area. 
We move the origin into the middle of the window. 
</p>

<pre class="explanation">
cr.Arc(0, 0, (width &lt; height ? width : height) / 2 - 10, 0, 2*Math.PI);
cr.StrokePreserve();
</pre>

<p>
We draw the outside shape of a circle. The <code>StrokePreserve()</code> 
strokes the current path according to the current line width, line join, line cap,
and dash settings. Unlike the <code>Stroke()</code>, 
it preserves the path within the cairo context. 
</p>

<pre class="explanation">
cr.SetSourceRGB(0.3, 0.4, 0.6);
cr.Fill();
</pre>

<p>
This fills the interior of the circle with some blue color.
</p>

<img src="/img/gui/sharpgtk/simpledrawing.png" alt="Simple drawing">
<div class="figure">Figure: Simple drawing</div>


<h2>Basic shapes</h2>

<p>
The next example draws some basic shapes onto the window. 
</p>

<div class="codehead">basicshapes.cs</div> 
<pre class="code">
using Gtk;
using Cairo;
using System;
 
class SharpApp : Window {
 

    public SharpApp() : base("Basic shapes")
    {
        SetDefaultSize(390, 240);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };
        
        DrawingArea darea = new DrawingArea();
        darea.ExposeEvent += OnExpose;

        Add(darea);
        ShowAll();
    }

    void OnExpose(object sender, ExposeEventArgs args)
    {
        DrawingArea area = (DrawingArea) sender;
        Cairo.Context cc =  Gdk.CairoHelper.Create(area.GdkWindow);
                
        cc.SetSourceRGB(0.2, 0.23, 0.9);
        cc.LineWidth = 1;

        cc.Rectangle(20, 20, 120, 80);
        cc.Rectangle(180, 20, 80, 80);
        cc.StrokePreserve();
        cc.SetSourceRGB(1, 1, 1);
        cc.Fill();

        cc.SetSourceRGB(0.2, 0.23, 0.9);
        cc.Arc(330, 60, 40, 0, 2*Math.PI);
        cc.StrokePreserve();
        cc.SetSourceRGB(1, 1, 1);
        cc.Fill();

        cc.SetSourceRGB(0.2, 0.23, 0.9);
        cc.Arc(90, 160, 40, Math.PI/4, Math.PI);
        cc.ClosePath();
        cc.StrokePreserve();
        cc.SetSourceRGB(1, 1, 1);
        cc.Fill();

        cc.SetSourceRGB(0.2, 0.23, 0.9);
        cc.Translate(220, 180);
        cc.Scale(1, 0.7);        
        cc.Arc(0, 0, 50, 0, 2*Math.PI);
        cc.StrokePreserve();
        cc.SetSourceRGB(1, 1, 1);
        cc.Fill();          

        ((IDisposable) cc.Target).Dispose ();                                      
        ((IDisposable) cc).Dispose ();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}
</pre>

<p>
In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. 
We draw outlines in blue color, insides in white. 
</p>

<pre class="explanation">
cc.Rectangle(20, 20, 120, 80);
cc.Rectangle(180, 20, 80, 80);
cc.StrokePreserve();
cc.SetSourceRGB(1, 1, 1);
cc.Fill();
</pre>

<p>
 These lines draw a rectangle and a square. 
</p>

<pre class="explanation">
cc.Arc(330, 60, 40, 0, 2*Math.PI);
</pre>

<p>
Here the <code>Arc()</code> method draws a full circle.
</p>

<pre class="explanation">
cc.Scale(1, 0.7);        
cc.Arc(0, 0, 50, 0, 2*Math.PI);
</pre>

<p>
If we want to draw an oval, we do some scaling first. Here the 
<code>Scale()</code> method shrinks the y axis.
</p>

<img src="/img/gui/sharpgtk/basicshapes.png" alt="Basic shapes">
<div class="figure">Figure: Basic shapes</div>

<h2>Colors</h2>

<p>
A color is an object representing a combination of Red, Green, and Blue (RGB) intensity values.
Cairo valid RGB values are in the range 0 to 1. 
</p>

<div class="codehead">colors.cs</div> 
<pre class="code">
using Gtk;
using Cairo;
using System;
 
class SharpApp : Window {
 

    public SharpApp() : base("Colors")
    {
        SetDefaultSize(360, 100);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };
        
        DrawingArea darea = new DrawingArea();
        darea.ExposeEvent += OnExpose;

        Add(darea);

        ShowAll();
    }

    void OnExpose(object sender, ExposeEventArgs args)
    {
        DrawingArea area = (DrawingArea) sender;
        Cairo.Context cr =  Gdk.CairoHelper.Create(area.GdkWindow);
                
        cr.SetSourceRGB(0.2, 0.23, 0.9);
        cr.Rectangle(10, 15, 90, 60);
        cr.Fill();
         
        cr.SetSourceRGB(0.9, 0.1, 0.1);
        cr.Rectangle(130, 15, 90, 60);
        cr.Fill();

        cr.SetSourceRGB(0.4, 0.9, 0.4);
        cr.Rectangle(250, 15, 90, 60);
        cr.Fill();

        ((IDisposable) cr.Target).Dispose();                                      
        ((IDisposable) cr).Dispose();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}
</pre>

<p>
We draw three rectangles in three different colors. . 
</p>

<pre class="explanation">
cr.SetSourceRGB(0.2, 0.23, 0.9);
</pre>

<p>
The <code>SetSourceRGB()</code> method sets a color for the 
cairo context. The three parameters of the method are the color intensity
values. 
</p>

<pre class="explanation">
cr.Rectangle(10, 15, 90, 60);
cr.Fill();
</pre>

<p>
We create a rectangle shape and fill it with the previously specified 
color. 
</p>

<img src="/img/gui/sharpgtk/colors.png" alt="Colors">
<div class="figure">Figure: Colors</div>


<h2>Transparent rectangles</h2>

<p>
Transparency is the quality of being able to see through a material. 
The easiest way to understand transparency is to imagine a piece of 
glass or water. Technically, the rays of light can go
through the glass and this way we can see objects behind the glass.
</p>

<p>
In computer graphics, we can achieve transparency effects using alpha 
compositing. Alpha compositing is the process of combining an image 
with a background to create the appearance of partial transparency. 
The composition process uses an alpha channel. (wikipedia.org, answers.com)
</p>

<div class="codehead">transparentrectangles.cs</div>
<pre class="code">
using Gtk;
using Cairo;
using System;
 

class SharpApp : Window {
 

    public SharpApp() : base("Transparent rectangles")
    {
        SetDefaultSize(590, 90);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); } ;
        
        DrawingArea darea = new DrawingArea();
        darea.ExposeEvent += OnExpose;

        Add(darea);

        ShowAll();
    }

    void OnExpose(object sender, ExposeEventArgs args)
    {
        DrawingArea area = (DrawingArea) sender;
        Cairo.Context cr =  Gdk.CairoHelper.Create(area.GdkWindow);

        for ( int i = 1; i <= 10; i++) {
            cr.SetSourceRGBA(0, 0, 1, i*0.1);
            cr.Rectangle(50*i, 20, 40, 40);
            cr.Fill();  
        }

        ((IDisposable) cr.Target).Dispose();                                      
        ((IDisposable) cr).Dispose();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}
</pre>

<p>
In the example we will draw ten rectangles with different levels of transparency. 
</p>

<pre class="explanation">
cr.SetSourceRGBA(0, 0, 1, i*0.1);
</pre>

<p>
The last parameter of the <code>SetSourceRGBA()</code> method is the
alpha transparency.
</p>

<img src="/img/gui/sharpgtk/transparency.png" alt="Transparent rectangles">
<div class="figure">Figure: Transparent rectangles</div>


<h2>Soulmate</h2>

<p>
In the next example, we draw some text on the window. 
</p>

<div class="codehead">soulmate.cs</div>
<pre class="code">
using Gtk;
using Cairo;
using System;
 
class SharpApp : Window {
 

    public SharpApp() : base("Soulmate")
    {
        SetDefaultSize(420, 250);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };
        
        DrawingArea darea = new DrawingArea();
        darea.ExposeEvent += OnExpose;

        Add(darea);

        ShowAll();
    }

    void OnExpose(object sender, ExposeEventArgs args)
    {
        DrawingArea area = (DrawingArea) sender;
        Cairo.Context cr =  Gdk.CairoHelper.Create(area.GdkWindow);
        
        cr.SetSourceRGB(0.1, 0.1, 0.1);
         
        cr.SelectFontFace("Purisa", FontSlant.Normal, FontWeight.Bold);
        cr.SetFontSize(13);
       
        cr.MoveTo(20, 30);
        cr.ShowText("Most relationships seem so transitory");
        cr.MoveTo(20, 60);
        cr.ShowText("They're all good but not the permanent one");
        cr.MoveTo(20, 120);
        cr.ShowText("Who doesn't long for someone to hold");
        cr.MoveTo(20, 150);
        cr.ShowText("Who knows how to love without being told");
        cr.MoveTo(20, 180);
        cr.ShowText("Somebody tell me why I'm on my own");
        cr.MoveTo(20, 210);
        cr.ShowText("If there's a soulmate for everyone");

        ((IDisposable) cr.Target).Dispose();                                      
        ((IDisposable) cr).Dispose();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}
</pre>

<p>
We display part of the lyrics from the Natasha Bedingfields Soulmate song. 
</p>

<pre class="explanation">
cr.SelectFontFace("Purisa", FontSlant.Normal, FontWeight.Bold);
</pre>

<p>
Here we specify the font, that we use. Purisa bold.
</p>

<pre class="explanation">
cr.SetFontSize(13);
</pre>

<p>
We specify the size of the font.
</p>

<pre class="explanation">
cr.MoveTo(20, 30);
</pre>

<p>
We move to the point, where we will draw the text. 
</p>

<pre class="explanation">
cr.ShowText("Most relationships seem so transitory");
</pre>

<p>
The <code>ShowText()</code> method draws text onto the window. 
</p>

<img src="/img/gui/sharpgtk/soulmate.png" alt="Soulmate">
<div class="figure">Figure: Soulmate</div>

<p>
In this chapter of the GTK# programming library, we were drawing 
with Cairo library.
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified January 24, 2009  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

